import { T_task } from '@/obj/class';
import { Tsrv, ifs, ts } from '@/services';
import axios from 'axios';
import { N_cPLDetails } from './types';

class T_cmd {
  // 主组件箱
  private compBox: ifs.I_compBox;

  // 主组件ID
  private compID: string;

  private task: T_task = new T_task(5000);

  // 主组件实例
  private self: N_cPLDetails.cPLDetails;

  // 编码组
  public ecDetCodeList: string[] = [];

  // 物理编号
  private physicalNum = ['my357'];

  // 零件编码
  private partCode: string[] = [
    'my862',
    'my863',
    'my864',
    'my865',
    'my866',
    'my867'
  ];

  // 零件数量
  private partNum: string[] = ['my868', 'my869', 'my870', 'my871'];

  // 写工艺参数成功或失败
  private writeSuccess: string[] = ['my1805', 'my1806'];

  // 服务器下发参数标志
  private writeFlag: string[] = ['my1807'];

  // 挂组加工完成后下线标志
  private writeHangGroup: string[] = ['my1808'];

  // 下料完成的挂组ID号
  private writeHangGroupId: string[] = ['my1809'];

  // 主组refs
  private topBaseGrid: any = null;

  // 判断启发是否完成
  private isOK = N_cPLDetails.V_schedulingStatus.NOTSTART;

  private headId: string = '';

  // 主组件created里初始化
  public init(self: N_cPLDetails.cPLDetails, compBoxInfo: ifs.I_compBoxInfo) {
    this.self = self;
    this.compBox = compBoxInfo.TcompBox;
    this.compID = compBoxInfo.compID;
  }

  public startTask() {
    this.task.addTask(this.readData);
    this.task.startTask();
  }

  public stopTask() {
    this.task.stopTask();
  }

  private readData = () => {
    Tsrv.standardPostReq<N_cPLDetails.I_readResp, any>(
      // my855编码为固定编码，循环读取是否上料完成
      // { ecDetCodes: ['my855'] },
      { ecDetCodes: this.ecDetCodeList },
      Tsrv.url.scadaRead
    ).then(([readResp, err]) => {
      if (!Tsrv.noValue(err)) {
        this.self.$msg(err);
        return;
      }
      if (!readResp.success) {
        this.self.$msg(readResp.msg);
        return;
      }
      // console.log('resp', readResp);
      if (this.ecDetCodeList[0] === 'my855') {
        if (readResp[this.ecDetCodeList[0]].v) {
          // 上料完成，开始读取
          this.ecDetCodeList = this.physicalNum.concat(
            this.partCode,
            this.partNum
          );
          this.readData();
        }
      } else {
        // 读取数据成功，开始写入数据库，并通知my855
        // 整理好json，调用event，写入'produc_line_detail_mgmt'与'hang_group_detail_mamt'两张表中
        this.insertData(readResp.data);
      }
    });
  };

  // 插入数据
  private async insertData(data: N_cPLDetails.I_readResp['data']) {
    // 找到数组中my357的v值，对应produc_line_detail_mgmt表的physical_num字段值
    const physical_num = data['my357'].v;
    const bpaBodyData: Array<Array<ifs.I_fv>> = [];
    // this.partCode.forEach((item, index) => {
    for (const [index, item] of this.partCode.entries()) {
      const partData: ifs.I_fv[] = [
        {
          field: 'id',
          value: await Tsrv.getSnowIDFmtStr()
        } as ifs.I_fv,
        {
          field: 'master_bill_id',
          value: this.headId
        } as ifs.I_fv,
        {
          field: 'category_number',
          value: data[item].v
        } as ifs.I_fv,
        {
          field: 'part_qty',
          value: data[this.partNum[index]].v
        } as ifs.I_fv
      ];
      bpaBodyData.push(partData);
    }
    // 插入数据使用bpa插入
    const bpa = new ts.T_bpaArg();
    const head = await this.getBpaHead({
      field: 'physical_num',
      value: physical_num
    } as ifs.I_fv);
    bpa.setHead(head).setBody(this.getBpaBody(bpaBodyData));
    // this.doEvent('插表api', array).then((b: boolean) => {
    //   if (b) {
    //     // 写表成功，通知my855
    //     this.writeData([
    //       {
    //         code: 'my855',
    //         value: 'false'
    //       }
    //     ]);
    //     // 加入过滤条件，只显示当前启动产线的挂组信息
    //     this.topBaseGrid.GT_editor.addInitFilter({
    //       field: 'master_bill_id',
    //       value: this.self.formData.id
    //     });
    //     // 刷新上表格
    //     this.topBaseGrid.GT_editor.loadTableData();
    //     // this.openScheduling(this.topBaseGrid.GT_editor.cloudData);
    //   }
    // });
  }

  private async getBpaHead(headInsRec: ifs.I_fv): Promise<ifs.I_bpaHead> {
    const o = new ts.T_bpaHead();
    const d = new ts.T_bpaHeadInsRec();
    const insertRecords: Array<ifs.I_fv> = [];
    this.headId = await Tsrv.getSnowIDFmtStr();
    insertRecords.push({
      field: 'id',
      value: this.headId
    } as ifs.I_fv);
    insertRecords.push(headInsRec);
    d.setDataRule({} as ifs.I_rule)
      .setFileInfo({})
      .setRowData(...insertRecords);
    o.setInsertRec(d);

    o.setFunName('produc_line_detail_mgmt')
      .setLang(this.self.$i18n.locale)
      .setDbType(Tsrv.globalVar.dbType.MYSQL)
      .setTableName('produc_line_detail_mgmt');
    return o;
  }

  private getBpaBody(bodyInsRec: Array<Array<ifs.I_fv>>): ifs.I_bpaBody {
    const o = new ts.T_bpaBody();
    o.rule = {} as ifs.I_rule;
    const d = new ts.T_bpaBodyInsRec();
    d.setScope({ field: 'master_bill_id', value: this.headId });
    if (Tsrv.noValue(bodyInsRec)) {
      d.data = [];
    } else {
      bodyInsRec.forEach(item => {
        const baseData = new ts.T_baseData();
        baseData
          .setRowData(...item)
          .setFileInfo({})
          .setDataRule({} as ifs.I_rule);
        d.data.push(baseData);
      });
    }
    o.data.push({
      tableName: 'hang_group_detail_mamt',
      dbType: Tsrv.globalVar.dbType.MYSQL,
      insertRecords: d
    });
    return o;
  }

  // 存在问题，定时任务开启时，五秒刷新一次，客户在操作本页面数据，会导致数据丢失
  private readData1 = () => {
    Tsrv.standardPostReq<N_cPLDetails.I_readResp, any>(
      // my855编码为固定编码，循环读取是否上料完成
      // { ecDetCodes: ['my855'] },
      { ecDetCodes: ['opctest2'] },
      Tsrv.url.scadaRead
    ).then(([readResp, err]) => {
      if (!Tsrv.noValue(err)) {
        this.self.$msg(err);
        return;
      }
      if (!readResp.success) {
        this.self.$msg(readResp.msg);
        return;
      }
      // my855通知服务器，生产线plc上料完成，服务器需要记录该挂组上料的全部信息
      // 包括： ID号  5个条码   5个数量   上料时间   操作人名字 工艺备注  系统自定义的参数   等信息
      // 从plc获取挂组ID号  5个条码   5个数量， 工件代号，上料时间   操作人名字 工艺备注

      // 根据读取的数据判断是否调用ctd写入数据库，判断字段待定？？？
      // ctd抽离，后续存在复用
      const ctd = new ts.T_ctdArg();
      ctd
        // .setTableName('produc_line_detail_mgmt')
        .setTableName('test1_plc_config')
        .setDbType(Tsrv.globalVar.dbType.MYSQL)
        .setRule({} as ifs.I_rule);
      const keys = Object.keys(readResp.data);
      keys.forEach(k => {
        if (!Tsrv.noValue(readResp.data[k])) {
          const datas = [];
          for (const key in readResp.data[k]) {
            if (key === 'v' || key === 'controllerType') {
              datas.push({
                field: key,
                value: readResp.data[k][key]
              });
            }
          }
          ctd.setInsRecDataOne({}, {} as ifs.I_rule, {}, ...datas);
        }
      });
      Tsrv.batRows(ctd).then(([b, res, msg]) => {
        if (!b) {
          this.self.$msg(msg);
        } else {
          // 加入当前过滤条件并刷新表格
          const oBaseGrid: any = this.self.$refs.xGrid;
          // 该处未测试
          oBaseGrid.GT_editor.addInitFilter({
            field: 'controllerType',
            value: 0
          });
          oBaseGrid.GT_editor.loadTableData();
          // this.openScheduling(oBaseGrid.cloudData);
        }
      });
    });
  };

  // 开启排程
  private openScheduling(datas: [any]) {
    // 找到master_bill_id为相同的行，存在
    const masterBillIds = datas.map((data: any) => data.master_bill_id);
    const uniqueMasterBillIds = Array.from(new Set(masterBillIds));
    let cancel;
    const cancelScheduling = new axios.CancelToken(function executor(c) {
      cancel = c;
    });
    uniqueMasterBillIds.forEach(el => {
      // 找到相同产线下并且状态为准备就绪的行
      const rows = datas.filter((data: any) => data.master_bill_id === el);
      // 当所有挂组状态中没有“等待”时，准备开始启发排程（加工中和加工完毕的挂组不在排产范围内）
      if (rows.every(row => row.f_status !== 0)) {
        const params = {
          ids: []
        };
        rows.forEach(row => {
          if (row.f_status === 1) {
            params.ids.push(row.id);
          }
        });
        // const params = this.topBaseGrid.GT_editor.getSelectedData(
        //   'cutsomRows',
        //   rows
        // );
        if (!Tsrv.noValue(params.ids)) {
          if (this.isOK === N_cPLDetails.V_schedulingStatus.RUNNING) {
            // 取消排程
            cancel(Tsrv.getI18nByValue('取消排程'));
          }
          this.isOK = N_cPLDetails.V_schedulingStatus.RUNNING;
          // 仿真排程是调用外部api
          axios
            .post<N_cPLDetails.I_schedulingResp>(
              'http://47.113.200.153:31301/xf/jointMes/api/layoutPart/orderToMock',
              params,
              { cancelToken: cancelScheduling }
            )
            .then((r: any) => {
              this.isOK = N_cPLDetails.V_schedulingStatus.FINISHED;
              if (r.success === true) {
                // 排程成功写入plc数据，槽体点位，编码等参数待定
                // 写入plc数据时，可能存在写入多个寄存器的情况，如该挂组制定的工艺流程的某一工序的槽体为具体的寄存器编码，寄存器的实际数据为指定温度，浓度，液位等
                // 对数据进行整理，传入event找到对应点位写入plc
                // this.writeData(r.data);
                this.standDoEvent('api2', 'produc_line_detail_mgmt', () => ({
                  data: {
                    ids: ['547242571294834688']
                  }
                })).then(res => {
                  if (res.isErr()) {
                    this.self.$msg(res.errmsg);
                  }
                });
                // 排程成功后修改状态为已排程并刷新表格
              }
            })
            .catch(thrown => {
              // 检查这个错误是否是一个取消请求的错误
              if (axios.isCancel(thrown)) {
                console.log('Request canceled', thrown.message);
              } else {
                // 处理其他类型的错误
                this.self.$msg(thrown.msg);
              }
            });
          // this.topBaseGrid.GT_editor.doEvent(
          //   'p_plan_analog_operation',
          //   params
          // ).then((r: any) =>
        }
      }
    });
  }

  private doEvent(apiName: string, params: any) {
    const layoutComp: any = this.self.$refs.layout;
    this.topBaseGrid = layoutComp.$children[0].$children[0];
    return this.topBaseGrid.GT_editor.doEvent(apiName, params);
  }

  public standDoEvent(apiName: string, tableName: string, params: any) {
    const funInfo = Tsrv.getFunInfo(tableName);
    return Tsrv.doEvent(apiName, funInfo, params);
  }

  public getTcmd(): T_cmd {
    return this;
  }

  public writeData(data: N_cPLDetails.I_writeCodeRes[]) {
    Tsrv.standardPostReq<N_cPLDetails.I_writeResp, N_cPLDetails.I_writeRes>(
      {
        writeList: data
      },
      Tsrv.url.scadaWrite
    ).then(([readResp, err]) => {
      if (!Tsrv.noValue(err)) {
        this.self.$msg(err);
      }
      console.log(readResp);
    });
  }
}
interface I_cmd extends T_cmd {}
export { I_cmd, T_cmd };
